﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using Microsoft.Extensions.DependencyInjection;
using Polly;
using RuYiAdmin.Net.Common.Global;
using RuYiAdmin.Net.Common.Utility;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace RuYiAdmin.Net.WebApi.AppCode.FrameworkExtensions
{
    public static class PollyHttpClientServiceCollectionExtensions
    {
        /// <summary>
        /// 注册Polly服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IServiceCollection AddHttpClientPolly(this IServiceCollection services, String name)
        {
            //降级回调
            var fallbackResponseMessage = new HttpResponseMessage
            {
                Content = new StringContent(RuYiAdminGlobalContext.PollyConfig.Message),
                StatusCode = HttpStatusCode.GatewayTimeout
            };

            // 配置httpClient
            services.AddHttpClient(name, c =>
            {
                var IP = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.
                FirstOrDefault(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.ToString();

                //基址
                c.BaseAddress = new System.Uri($"http://{IP}:{RuYiAdminGlobalContext.ConsulConfig.ServicePort}");
            })
            //降级策略
            .AddPolicyHandler(Policy<HttpResponseMessage>.HandleInner<Exception>().FallbackAsync(fallbackResponseMessage, async b =>
            {
                //降级打印异常
                Console.WriteLine($"服务{name}开始降级,异常消息：{b.Exception.Message}");

                //降级后的数据
                Console.WriteLine($"服务{name}降级内容响应：{fallbackResponseMessage.Content.ToString()}");

                await Task.CompletedTask;
            }))
            //断路器策略
            .AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(RuYiAdminGlobalContext.PollyConfig.OpenFallCount,
            TimeSpan.FromSeconds(RuYiAdminGlobalContext.PollyConfig.DownTime), (ex, ts) =>
            {
                var title = $"服务{name}断路器开启，异常消息：{ex.Exception.Message}";
                Console.WriteLine(title);

                var content = $"服务{name}断路器开启时间：{ts.TotalSeconds}s";
                Console.WriteLine(content);

                content += "\r\n" + $"InnerException:{ex.Exception.InnerException}";
                content += "\r\n" + $"Source:{ex.Exception.Source}";
                content += "\r\n" + $"StackTrace:{ex.Exception.StackTrace}";

                //熔断告警邮件服务
                RuYiMailUtil.SendMail(title, content, RuYiAdminGlobalContext.PollyConfig.OMMailbox);
            }, () =>
            {
                Console.WriteLine($"服务{name}断路器关闭");
            }, () =>
            {
                Console.WriteLine($"服务{name}断路器半开启(时间控制，自动开关)");
            }))
            //重试策略
            .AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().RetryAsync(RuYiAdminGlobalContext.PollyConfig.RetryCount)
            )
            //超时策略
            .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(RuYiAdminGlobalContext.PollyConfig.Timeout)));

            return services;
        }
    }
}
